package home

import (
	"bufio"
	"fmt"
	"os"
	"sort"
	"strings"
	"sync"
)

const B_WID = 3

var bls = [][]uint8{
	{0, 0},
	{0, 1},
	{1, 0},
	{1, 1},
}

type chk struct {
	b      bool
	f1, f2 FyArr
}

type sort_chk []chk

func (c sort_chk) Len() int      { return len(c) }
func (c sort_chk) Swap(i, j int) { c[i], c[j] = c[j], c[i] }
func (c sort_chk) Less(i, j int) bool {
	if c[i].f2.idx < c[j].f2.idx {
		return false
	}
	if c[i].f2.idx > c[j].f2.idx {
		return true
	}
	if c[i].f2.idx == c[j].f2.idx {
		if c[i].f1.idx < c[j].f1.idx {
			return false
		}
		if c[i].f1.idx > c[j].f1.idx {
			return true
		}
	}
	return true
}

func check1(f1, f2 FnTy) bool {
	rtb := true
	for _, v := range bls {
		a, b := v[0], v[1]
		if f1(a, b) != f2(a, b) {
			rtb = false
			break
		}
	}
	return rtb
}

func check2(f1, f2 FnTy) bool {
	rtb := true
	for _, v := range O_A {
		a, b := v[0], v[1]
		if f1(a, b) != f2(a, b) {
			rtb = false
			break
		}
	}
	return rtb
}

func filt1() {
	var l1 int = len(FS0)

	c1 := make(chan chk, l1*l1)
	var wg sync.WaitGroup

	for i := 0; i < l1; i++ {
		for j := i + 1; j < l1; j++ {
			wg.Add(1)
			go func(a, b int) {
				defer wg.Done()
				c1 <- chk{
					b:  check1(FS0[a].fn, FS0[b].fn),
					f1: FS0[a],
					f2: FS0[b],
				}
			}(i, j)
		}
	}

	go func() {
		wg.Wait()
		close(c1)
	}()

	// {true 9 10} {true 2 11}
	for elm := range c1 {
		if elm.b {
			fmt.Printf("%d: %s <==> %d: %s \n", elm.f1.idx, elm.f1.str, elm.f2.idx, elm.f2.str)
		}

	}
}

func filt2() {

	var l1 int = len(FS0I)
	var fs2 []FyArr
	var begin int = 20

	for i := 0; i < l1; i++ {
		for j := 0; j < B_WID; j++ {
			// 要修复“闭包捕获循环变量”的问题，你需要确保在每次迭代中捕获i和j的当前值。
			c_i, c_j := uint8(i), uint8(j)
			// sj:= strconv.FormatUint(uint64(c_j),2)
			e := begin + len(fs2)

			fs2 = append(fs2, FyArr{
				idx: e + 1,
				str: strings.ReplaceAll(FS0I[c_i].str, "p", fmt.Sprintf("(0b%03b&p)", c_j)),
				fn: func(p, n uint8) uint8 {
					return FS0I[c_i].fn(c_j&p, n)
				}})
			fs2 = append(fs2, FyArr{
				idx: e + 2,
				str: strings.ReplaceAll(FS0I[c_i].str, "p", fmt.Sprintf("(0b%03b|p)", c_j)),
				fn: func(p, n uint8) uint8 {
					return FS0I[c_i].fn(c_j|p, n)
				}})
			fs2 = append(fs2, FyArr{
				idx: e + 3,
				str: strings.ReplaceAll(FS0I[c_i].str, "p", fmt.Sprintf("(0b%03b^p)", c_j)),
				fn: func(p, n uint8) uint8 {
					return FS0I[c_i].fn(c_j^p, n)
				}})
			fs2 = append(fs2, FyArr{
				idx: e + 4,
				str: strings.ReplaceAll(FS0I[c_i].str, "n", fmt.Sprintf("(0b%03b&n)", c_j)),
				fn: func(p, n uint8) uint8 {
					return FS0I[c_i].fn(p, c_j&n)
				}})
			fs2 = append(fs2, FyArr{
				idx: e + 5,
				str: strings.ReplaceAll(FS0I[c_i].str, "n", fmt.Sprintf("(0b%03b|n)", c_j)),
				fn: func(p, n uint8) uint8 {
					return FS0I[c_i].fn(p, c_j|n)
				}})
			fs2 = append(fs2, FyArr{
				idx: e + 6,
				str: strings.ReplaceAll(FS0I[c_i].str, "n", fmt.Sprintf("(0b%03b^n)", c_j)),
				fn: func(p, n uint8) uint8 {
					return FS0I[c_i].fn(p, c_j^n)
				}})

		}
	}

	l2 := len(fs2)
	c1 := make(chan chk, l2*l2)
	var wg sync.WaitGroup

	for i := 0; i < l2; i++ {
		for j := i + 1; j < l2; j++ {
			wg.Add(1)
			go func(a, b int) {
				defer wg.Done()
				c1 <- chk{
					b:  check2(fs2[a].fn, fs2[b].fn),
					f1: fs2[a],
					f2: fs2[b],
				}
			}(i, j)
		}
	}

	go func() {
		wg.Wait()
		close(c1)
	}()

	var ckr []chk

	for elm := range c1 {
		if elm.b {
			// fmt.Printf("%d: %s <==> %d: %s \n", elm.f1.idx, elm.f1.str, elm.f2.idx, elm.f2.str)
			ckr = append(ckr, elm)
		}
	}

	sort.Sort(sort_chk(ckr))

	var del = make(map[int]struct{}, len(ckr))
	for _, elm := range ckr {
		fmt.Printf("%4d: %s <==> %4d: %s \n", elm.f1.idx, elm.f1.str, elm.f2.idx, elm.f2.str)
		del[elm.f2.idx] = struct{}{}
	}

	fmt.Printf("\n =========== SIZE fs2 : %d ===========\n", len(fs2))
	var fs3 []FyArr
	for _, v := range fs2 {
		_, d := del[v.idx]
		if d {
			continue
		}
		fs3 = append(fs3, v)
	}
	fmt.Printf("\n =========== SIZE fs3 : %d ===========\n", len(fs3))

	f, err := os.Create("./tmp/fs2F.txt")
	Check_err(err)

	defer f.Close()

	w := bufio.NewWriter(f)
	for _, fa := range fs3 {
		_, err := w.WriteString(fmt.Sprintf(
			"{idx: %4d, str: \"%s\", fn: func(p, n uint8) uint8 { return %s }},\n",
			fa.idx, fa.str, fa.str))
		Check_err(err)
	}

	w.Flush()
}

func filt3() {
	var l1 int = len(FS0I)
	var fs2 []FyArr
	var begin int = 200
	for i := 0; i < l1; i++ {

		// 要修复“闭包捕获循环变量”的问题，你需要确保在每次迭代中捕获i和j的当前值。
		c_i := uint8(i)
		// sj:= strconv.FormatUint(uint64(c_j),2)
		e := begin + len(fs2)

		fs2 = append(fs2, FyArr{
			idx: e + 1,
			str: strings.ReplaceAll(FS0I[c_i].str, "p", "Mv_l1(p)"),
			fn: func(p, n uint8) uint8 {
				return FS0I[c_i].fn(Mv_l1(p), n)
			}})
		fs2 = append(fs2, FyArr{
			idx: e + 2,
			str: strings.ReplaceAll(FS0I[c_i].str, "p", "Mv_l2(p)"),
			fn: func(p, n uint8) uint8 {
				return FS0I[c_i].fn(Mv_l2(p), n)
			}})
		fs2 = append(fs2, FyArr{
			idx: e + 3,
			str: strings.ReplaceAll(FS0I[c_i].str, "n", "Mv_l1(n)"),
			fn: func(p, n uint8) uint8 {
				return FS0I[c_i].fn(p, Mv_l1(n))
			}})
		fs2 = append(fs2, FyArr{
			idx: e + 4,
			str: strings.ReplaceAll(FS0I[c_i].str, "n", "Mv_l2(n)"),
			fn: func(p, n uint8) uint8 {
				return FS0I[c_i].fn(p, Mv_l2(n))
			}})

	}

	l2 := len(fs2)
	c1 := make(chan chk, l2*l2)
	var wg sync.WaitGroup

	for i := 0; i < l2; i++ {
		for j := i + 1; j < l2; j++ {
			wg.Add(1)
			go func(a, b int) {
				defer wg.Done()
				c1 <- chk{
					b:  check2(fs2[a].fn, fs2[b].fn),
					f1: fs2[a],
					f2: fs2[b],
				}
			}(i, j)
		}
	}

	go func() {
		wg.Wait()
		close(c1)
	}()

	var ckr []chk

	for elm := range c1 {
		if elm.b {
			// fmt.Printf("%d: %s <==> %d: %s \n", elm.f1.idx, elm.f1.str, elm.f2.idx, elm.f2.str)
			ckr = append(ckr, elm)
		}
	}

	sort.Sort(sort_chk(ckr))

	var del = make(map[int]struct{}, len(ckr))
	for _, elm := range ckr {
		fmt.Printf("%4d: %s <==> %4d: %s \n", elm.f1.idx, elm.f1.str, elm.f2.idx, elm.f2.str)
		del[elm.f2.idx] = struct{}{}
	}

	fmt.Printf("\n =========== SIZE fs2 : %d ===========\n", len(fs2))
	var fs3 []FyArr
	for _, v := range fs2 {
		_, d := del[v.idx]
		if d {
			continue
		}
		fs3 = append(fs3, v)
	}
	fmt.Printf("\n =========== SIZE fs3 : %d ===========\n", len(fs3))

	f, err := os.Create("./tmp/fs3F.txt")
	Check_err(err)

	defer f.Close()

	w := bufio.NewWriter(f)
	for _, fa := range fs3 {
		_, err := w.WriteString(fmt.Sprintf(
			"{idx: %4d, str: \"%s\", fn: func(p, n uint8) uint8 { return %s }},\n",
			fa.idx, fa.str, fa.str))
		Check_err(err)
	}

	w.Flush()
}

func filt23() {
	var l1 int = len(FS2B)
	var fs2 []FyArr
	var begin int = 300

	for i := 0; i < l1; i++ {
		for j := 0; j < B_WID; j++ {
			// 要修复“闭包捕获循环变量”的问题，你需要确保在每次迭代中捕获i和j的当前值。
			c_i, c_j := uint8(i), uint8(j)
			// sj:= strconv.FormatUint(uint64(c_j),2)
			e := begin + len(fs2)

			fs2 = append(fs2, FyArr{
				idx: e + 1,
				str: strings.ReplaceAll(FS2B[c_i].str, "p", fmt.Sprintf("(0b%03b&p)", c_j)),
				fn: func(p, n uint8) uint8 {
					return FS2B[c_i].fn(c_j&p, n)
				}})
			fs2 = append(fs2, FyArr{
				idx: e + 2,
				str: strings.ReplaceAll(FS2B[c_i].str, "p", fmt.Sprintf("(0b%03b|p)", c_j)),
				fn: func(p, n uint8) uint8 {
					return FS2B[c_i].fn(c_j|p, n)
				}})
			fs2 = append(fs2, FyArr{
				idx: e + 3,
				str: strings.ReplaceAll(FS2B[c_i].str, "p", fmt.Sprintf("(0b%03b^p)", c_j)),
				fn: func(p, n uint8) uint8 {
					return FS2B[c_i].fn(c_j^p, n)
				}})
			fs2 = append(fs2, FyArr{
				idx: e + 4,
				str: strings.ReplaceAll(FS2B[c_i].str, "n", fmt.Sprintf("(0b%03b&n)", c_j)),
				fn: func(p, n uint8) uint8 {
					return FS2B[c_i].fn(p, c_j&n)
				}})
			fs2 = append(fs2, FyArr{
				idx: e + 5,
				str: strings.ReplaceAll(FS2B[c_i].str, "n", fmt.Sprintf("(0b%03b|n)", c_j)),
				fn: func(p, n uint8) uint8 {
					return FS2B[c_i].fn(p, c_j|n)
				}})
			fs2 = append(fs2, FyArr{
				idx: e + 6,
				str: strings.ReplaceAll(FS2B[c_i].str, "n", fmt.Sprintf("(0b%03b^n)", c_j)),
				fn: func(p, n uint8) uint8 {
					return FS2B[c_i].fn(p, c_j^n)
				}})

		}
	}

	l2 := len(fs2)
	c1 := make(chan chk, l2*l2)
	var wg sync.WaitGroup

	for i := 0; i < l2; i++ {
		for j := i + 1; j < l2; j++ {
			wg.Add(1)
			go func(a, b int) {
				defer wg.Done()
				c1 <- chk{
					b:  check2(fs2[a].fn, fs2[b].fn),
					f1: fs2[a],
					f2: fs2[b],
				}
			}(i, j)
		}
	}

	go func() {
		wg.Wait()
		close(c1)
	}()

	var ckr []chk

	for elm := range c1 {
		if elm.b {
			// fmt.Printf("%d: %s <==> %d: %s \n", elm.f1.idx, elm.f1.str, elm.f2.idx, elm.f2.str)
			ckr = append(ckr, elm)
		}
	}

	sort.Sort(sort_chk(ckr))

	var del = make(map[int]struct{}, len(ckr))
	for _, elm := range ckr {
		fmt.Printf("%4d: %s <==> %4d: %s \n", elm.f1.idx, elm.f1.str, elm.f2.idx, elm.f2.str)
		del[elm.f2.idx] = struct{}{}
	}

	fmt.Printf("\n =========== SIZE fs2 : %d ===========\n", len(fs2))
	var fs3 []FyArr
	for _, v := range fs2 {
		_, d := del[v.idx]
		if d {
			continue
		}
		fs3 = append(fs3, v)
	}
	fmt.Printf("\n =========== SIZE fs3 : %d ===========\n", len(fs3))

	f, err := os.Create("./tmp/fs23F.txt")
	Check_err(err)

	defer f.Close()

	w := bufio.NewWriter(f)
	for _, fa := range fs3 {
		_, err := w.WriteString(fmt.Sprintf(
			"{idx: %4d, str: \"%s\", fn: func(p, n uint8) uint8 { return %s }},\n",
			fa.idx, fa.str, fa.str))
		Check_err(err)
	}

	w.Flush()

}

func filt32() {
	var l1 int = len(FS2A)
	var fs2 []FyArr
	var begin int = 1200
	for i := 0; i < l1; i++ {

		// 要修复“闭包捕获循环变量”的问题，你需要确保在每次迭代中捕获i和j的当前值。
		c_i := uint8(i)
		// sj:= strconv.FormatUint(uint64(c_j),2)
		e := begin + len(fs2)

		fs2 = append(fs2, FyArr{
			idx: e + 1,
			str: strings.ReplaceAll(FS2A[c_i].str, "p", "Mv_l1(p)"),
			fn: func(p, n uint8) uint8 {
				return FS2A[c_i].fn(Mv_l1(p), n)
			}})
		fs2 = append(fs2, FyArr{
			idx: e + 2,
			str: strings.ReplaceAll(FS2A[c_i].str, "p", "Mv_l2(p)"),
			fn: func(p, n uint8) uint8 {
				return FS2A[c_i].fn(Mv_l2(p), n)
			}})
		fs2 = append(fs2, FyArr{
			idx: e + 3,
			str: strings.ReplaceAll(FS2A[c_i].str, "n", "Mv_l1(n)"),
			fn: func(p, n uint8) uint8 {
				return FS2A[c_i].fn(p, Mv_l1(n))
			}})
		fs2 = append(fs2, FyArr{
			idx: e + 4,
			str: strings.ReplaceAll(FS2A[c_i].str, "n", "Mv_l2(n)"),
			fn: func(p, n uint8) uint8 {
				return FS2A[c_i].fn(p, Mv_l2(n))
			}})

	}

	l2 := len(fs2)
	c1 := make(chan chk, l2*l2)
	var wg sync.WaitGroup

	for i := 0; i < l2; i++ {
		for j := i + 1; j < l2; j++ {
			wg.Add(1)
			go func(a, b int) {
				defer wg.Done()
				c1 <- chk{
					b:  check2(fs2[a].fn, fs2[b].fn),
					f1: fs2[a],
					f2: fs2[b],
				}
			}(i, j)
		}
	}

	go func() {
		wg.Wait()
		close(c1)
	}()

	var ckr []chk

	for elm := range c1 {
		if elm.b {
			// fmt.Printf("%d: %s <==> %d: %s \n", elm.f1.idx, elm.f1.str, elm.f2.idx, elm.f2.str)
			ckr = append(ckr, elm)
		}
	}

	sort.Sort(sort_chk(ckr))

	var del = make(map[int]struct{}, len(ckr))
	for _, elm := range ckr {
		fmt.Printf("%4d: %s <==> %4d: %s \n", elm.f1.idx, elm.f1.str, elm.f2.idx, elm.f2.str)
		del[elm.f2.idx] = struct{}{}
	}

	fmt.Printf("\n =========== SIZE fs2 : %d ===========\n", len(fs2))
	var fs3 []FyArr
	for _, v := range fs2 {
		_, d := del[v.idx]
		if d {
			continue
		}
		fs3 = append(fs3, v)
	}
	fmt.Printf("\n =========== SIZE fs3 : %d ===========\n", len(fs3))

	f, err := os.Create("./tmp/fs32F.txt")
	Check_err(err)

	defer f.Close()

	w := bufio.NewWriter(f)
	for _, fa := range fs3 {
		_, err := w.WriteString(fmt.Sprintf(
			"{idx: %4d, str: \"%s\", fn: func(p, n uint8) uint8 { return %s }},\n",
			fa.idx, fa.str, fa.str))
		Check_err(err)
	}

	w.Flush()
}

func filt4() {
	var l2 int = len(FS3H)
	c1 := make(chan chk, l2*l2)
	var wg sync.WaitGroup

	for i := 0; i < l2; i++ {
		for j := i + 1; j < l2; j++ {
			wg.Add(1)
			go func(a, b int) {
				defer wg.Done()
				c1 <- chk{
					b:  check2(FS3H[a].fn, FS3H[b].fn),
					f1: FS3H[a],
					f2: FS3H[b],
				}
			}(i, j)
		}
	}

	go func() {
		wg.Wait()
		close(c1)
	}()

	var ckr []chk

	for elm := range c1 {
		if elm.b {
			// fmt.Printf("%d: %s <==> %d: %s \n", elm.f1.idx, elm.f1.str, elm.f2.idx, elm.f2.str)
			ckr = append(ckr, elm)
		}
	}

	sort.Sort(sort_chk(ckr))

	var del = make(map[int]struct{}, len(ckr))
	for _, elm := range ckr {
		fmt.Printf("%4d: %s <==> %4d: %s \n", elm.f1.idx, elm.f1.str, elm.f2.idx, elm.f2.str)
		del[elm.f2.idx] = struct{}{}
	}

	fmt.Printf("\n =========== SIZE fs2 : %d ===========\n", len(FS3H))
	var fs3 []FyArr
	for _, v := range FS3H {
		_, d := del[v.idx]
		if d {
			continue
		}
		fs3 = append(fs3, v)
	}
	fmt.Printf("\n =========== SIZE fs3 : %d ===========\n", len(fs3))

	f, err := os.Create("./tmp/fs4F.txt")
	Check_err(err)

	defer f.Close()

	w := bufio.NewWriter(f)
	for _, fa := range fs3 {
		_, err := w.WriteString(fmt.Sprintf(
			"{idx: %4d, str: \"%s\", fn: func(p, n uint8) uint8 { return %s }},\n",
			fa.idx, fa.str, fa.str))
		Check_err(err)
	}

	w.Flush()

}
